package com.sheepone.util.beanconvert.excel;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.sheepone.util.ClassUtil;
import org.apache.poi.ss.formula.functions.T;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Array;
import java.util.List;

/**
 * @author Miss.杨
 * @description 将excel文件转换成JavaBean对象
 * @since 2024/2/20 - 21:58
 */
public class ExcelBeanConvertUtil {
    private ExcelBeanConvertUtil() {
    }

    private static final Logger logger = LoggerFactory.getLogger(new Object() {
    }.getClass().getEnclosingClass());


    public static double[] parseDoubleColumn(String filePath, int column) {
        return parseDoubleColumn(filePath, 0, column);
    }

    private static double[] parseDoubleColumn(String filePath, int sheet, int column) {
        return parseDoubleColumn(filePath, sheet, column, -1);
    }

    private static double[] parseDoubleColumn(String filePath, int sheet, int column, int lineNum) {
        return new double[0];
    }

    /**
     * 将Excel文件解析成JavaBean数组对象，默认 sheet序号为0，开启驼峰映射,读取全部行
     *
     * @param filePath 待解析的文件路径
     * @param clazz    JavaBean类型
     * @return 解析后的数组
     */
    public static <T> T[] parseArray(String filePath, Class<T> clazz) {
        return parseArray(filePath, 0, clazz);
    }


    /**
     * 将Excel文件解析成JavaBean数组对象，默认开启驼峰映射,读取全部行
     *
     * @param filePath 待解析的文件路径
     * @param sheet    sheet序号
     * @param clazz    JavaBean类型
     * @return 数组集合
     */
    public static <T> T[] parseArray(String filePath, int sheet, Class<T> clazz) {
        return parseArray(filePath, sheet, -1, clazz);
    }

    /**
     * 将Excel文件解析成JavaBean数组对象，开启驼峰映射
     *
     * @param filePath 待解析的文件路径
     * @param sheet    sheet序号
     * @param clazz    JavaBean类型
     * @param lineNum  从0开始读取lineNum行
     * @return 数组集合
     */
    public static <T> T[] parseArray(String filePath, int sheet, int lineNum, Class<T> clazz) {
        return parseArray(filePath, sheet, lineNum, clazz, true);
    }

    /**
     * 将Excel文件解析成JavaBean数组对象
     *
     * @param filePath          待解析的文件路径
     * @param sheet             sheet序号
     * @param lineNum           从0开始读取lineNum行
     * @param clazz             JavaBean类型
     * @param enableHumpMapping 是否开启驼峰映射
     * @return 数组集合
     */
    public static <T> T[] parseArray(String filePath, int sheet, int lineNum, Class<T> clazz, boolean enableHumpMapping) {
        List<T> list = parseList(filePath, sheet, lineNum, clazz, enableHumpMapping);
        T[] array = (T[]) Array.newInstance(clazz, list.size());
        list.toArray(array);
        return array;
    }

    /**
     * 将Excel文件解析成JavaBean的List对象，默认 sheet序号为0，开启驼峰映射，读取全部列
     *
     * @param filePath 待解析的文件路径
     * @param clazz    JavaBean类型
     * @return list集合
     */
    public static <T> List<T> parseList(String filePath, Class<T> clazz) {
        return parseList(filePath, 0, clazz);
    }

    /**
     * 将Excel文件解析成JavaBean的List对象，默认开启驼峰映射,读取全部列
     *
     * @param filePath 待解析的文件路径
     * @param sheet    sheet序号
     * @param clazz    JavaBean类型
     * @return list集合
     */
    public static <T> List<T> parseList(String filePath, int sheet, Class<T> clazz) {
        return parseList(filePath, sheet, -1, clazz, true);
    }


    /**
     * 将Excel文件解析成JavaBean的List对象，默认开启驼峰映射
     *
     * @param filePath 待解析的文件路径
     * @param sheet    sheet序号
     * @param lineNum  从0开始读取lineNum行
     * @param clazz    JavaBean类型
     * @return list集合
     */
    public static <T> List<T> parseList(String filePath, int sheet, int lineNum, Class<T> clazz) {
        return parseList(filePath, sheet, lineNum, clazz, true);
    }

    /**
     * 将Excel文件解析成JavaBean的List对象
     *
     * @param filePath          待解析的文件路径
     * @param sheet             sheet序号
     * @param lineNum           从0开始读取lineNum行
     * @param clazz             JavaBean类型
     * @param enableHumpMapping 是否开启驼峰映射
     * @return list集合
     */
    public static <T> List<T> parseList(String filePath, int sheet, int lineNum, Class<T> clazz, boolean enableHumpMapping) {
        SingleTypeExcelParser<T> listener = new SingleTypeExcelParser<>(clazz, lineNum, enableHumpMapping);
        EasyExcel.read(filePath, clazz, listener).ignoreEmptyRow(true).sheet(sheet).doRead();
        return listener.getData();
    }

    public static <T> List<T> parseList(InputStream inputStream, Class<T> clazz) {
        return parseList(inputStream, 0, clazz);
    }

    public static <T> List<T> parseList(InputStream inputStream, int sheet, Class<T> clazz) {
        return parseList(inputStream, sheet, -1, clazz);
    }

    public static <T> List<T> parseList(InputStream inputStream, int sheet, int lineNum, Class<T> clazz) {
        return parseList(inputStream, sheet, lineNum, clazz, true);
    }

    public static <T> List<T> parseList(InputStream inputStream, int sheet, int lineNum, Class<T> clazz, boolean enableHumpMapping) {
        SingleTypeExcelParser<T> listener = new SingleTypeExcelParser<>(clazz, lineNum, enableHumpMapping);
        EasyExcel.read(inputStream, clazz, listener).ignoreEmptyRow(true).sheet(sheet).doRead();
        return listener.getData();
    }


    public static <T> void writeToOutputStream(List<T> dataList, int sheet, OutputStream out) {
        if (dataList == null || dataList.isEmpty()) {
            return;
        }
        Class<T> componentType = ClassUtil.getComponentType(dataList);
        EasyExcel.write(out, componentType)
                .needHead(true)
                .excelType(ExcelTypeEnum.XLSX)
                .sheet(sheet)
                .doWrite(dataList);
    }

    public static <T> void writeToFile(List<T> dataList, int sheet, String path) {
        if (dataList == null || dataList.isEmpty()) {
            return;
        }
        Class<T> componentType = ClassUtil.getComponentType(dataList);
        EasyExcel.write(path, componentType)
                .excelType(ExcelTypeEnum.XLSX)
                .needHead(true)
                .sheet(sheet)
                .doWrite(dataList);
    }
}
